package server;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.concurrent.BrokenBarrierException;

import smash_tris.DataPacket;
import smash_tris.Player;
import smash_tris.Room;
import smash_tris.TypeOfDataPacket;

/**
 * Obiekt umozliwiający komunikację pomiędzy graczami w tym samym pokoju.
 * 
 * @author Pawel Rychly
 * @author Maciej Graszek
 * 
 */
public class GameRoomCommunication implements Runnable {

	private Room room = null;
	private ArrayList<ObjectInputStream> inPlayer = new ArrayList<ObjectInputStream>(
			2);
	private ArrayList<ObjectOutputStream> outPlayer = new ArrayList<ObjectOutputStream>(
			2);
	private boolean isPlayerReady[] = { false, false };
	private boolean isRunning = false;
	private Integer counter = 0;
	private Player player = null;
	private Thread thread = null;
	private boolean inRun = false;
	private SmashTrisManager manager = null;

	Integer numOfStarters = 0;

	/**
	 * Konstruktor
	 * 
	 * @param room
	 *            pokój w którym odbywa się rozgrywka.
	 * @param in
	 * @param out
	 */
	public GameRoomCommunication(Room room, ObjectInputStream in,
			ObjectOutputStream out, SmashTrisManager manager) {
		this.room = room;
		inPlayer.add(in);
		outPlayer.add(out);
		
		this.manager = manager;
		// TODO Auto-generated constructor stub
	}

	/**
	 * Konstruktor umożliwiający dołączenie gracza do pokoju.
	 * 
	 * @param in
	 * @param out
	 */
	public synchronized void joinToGameRoom(ObjectInputStream in,
			ObjectOutputStream out) {
		inPlayer.add(in);
		outPlayer.add(out);
		// isPlayerReady[0] = true;
		// isPlayerReady[1] = true;
		// System.out.println("joinToGameRoom!!!");
		// startGame();
	}

	public synchronized Room removeFromRoom(Player player, Room room) {

	
		if (this.room.getPlayers().size() > 1) {
			
			for (int i = 0; i < this.room.getPlayers().size(); i++) {
				if (player.getId() == this.room.getPlayers().get(i).getId()) {
					this.inPlayer.remove(i);
					this.outPlayer.remove(i);
				}
			}
			room.removePlayer(player);
			this.room.setRoomMaster(this.room.getPlayers().get(0));
			
		} else {
			this.room.getPlayers().clear();
			this.inPlayer.clear();
			this.outPlayer.clear();
		}
		

		
		return this.room;
	}
	
	/**
	 * Metoda rozpoczyna rozgrywkę.
	 */
	private boolean isReadyTostartGame() {
		if ((isRunning == false) && (isPlayerReady[0] == true)
				&& (isPlayerReady[1] == true)) {
			thread = new Thread(this);

			/*
			 * try { //t.join(); } catch (InterruptedException e) { // TODO
			 * Auto-genera e.printStackTrace(); }
			 */
			return true;
		}
		return false;
	}

	public void setStart() {
		if (numOfStarters == 2) {
			numOfStarters = 0;
		}
		numOfStarters++;
		if (numOfStarters == 2) {
			thread.start();
			isRunning = true;
		}

	}

	/**
	 * Metoda zwraca informację czy rozgrywka się toczy.
	 * 
	 * @return
	 */
	public boolean isRunning() {
		return isRunning;
	}

	/**
	 * Zmienia stan gracza z oczekującego na gotowego lub odwrotnie.
	 * 
	 * @param player
	 */
	public synchronized Integer setReady(Player player) {

		Integer i = room.getIndexOfPlayer(player);
		if (i != -1) {
			if (isPlayerReady[i] == true) {
				isPlayerReady[i] = false;
				return 0; // ready odznaczony.
			} else {
				this.player = player;
				isPlayerReady[i] = true;
				if (this.isReadyTostartGame()) {
					return 2; // rozpoczęto grę.
				} else {
					return 1; // ustawiono ready.
				}
			}
		} else {
			return 0; // ready odznaczony.
		}
	}

	public void joinGameThread() {
		while (thread == null) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		try {
			thread.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

	public void notifyPlayer() {

		while (thread == null) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		try {
			while (!inRun) {
				
				synchronized (player) {
					player.notify();
					
				}
			}
			thread.join();

			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	@Override
	public void run() {
		System.out.println("Game is running...");
		DataPacket userInput;
		synchronized (player) {
			try {
				player.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		inRun = true;

		try {
			Integer i = 0;
			outPlayer.get(0).reset();
			outPlayer.get(1).reset();
			outPlayer.get(i).writeObject(
					new DataPacket(TypeOfDataPacket.START_GAME, null));
			outPlayer.get(i).flush();

			while (isRunning) {
				while ((isRunning)
						&& (userInput = (DataPacket) inPlayer.get(i)
								.readObject()) != null) {

					switch (userInput.getTypeOfInformation()) {
					case STATE_OF_GAME:
						StateOfGame state = (StateOfGame) userInput.getData();

						// Przesłanie danych do przeciwnika
						outPlayer.get(1 - i).writeObject(
								new DataPacket(TypeOfDataPacket.STATE_OF_GAME,
										state));
						outPlayer.get(1 - i).flush();
						// Przesłanie potwierdzenia.
						break;
					case EXIT_FROM_ROOM:
						DataPacket data = new DataPacket(
								TypeOfDataPacket.EXIT_FROM_ROOM, null);
						outPlayer.get(1 - i).writeObject(
								new DataPacket(TypeOfDataPacket.EXIT_FROM_ROOM,
										null));
						outPlayer.get(1 - i).flush();
						while (isRunning) {
							while ((isRunning)
									&& (userInput = (DataPacket) inPlayer.get(
											1 - i).readObject()) != null) {
								if (userInput.getTypeOfInformation() == TypeOfDataPacket.RESPONSE_OK) {
									isRunning = false;
								}
							}
						}
						manager.broadcastToPlayers(this.room.getPlayers(),
								TypeOfDataPacket.EXIT_FROM_ROOM, null);

						manager.removeGameRoom(room);

						break;
					}
					
					outPlayer.get(i).reset();
					outPlayer.get(i).reset();

					if (!isRunning) {
						System.out.println("exit");
					}
					counter++;
					i = counter % 2;
					
				}

			}
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			System.out.println("Przerwany potok");

			// e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

}
